package cn.seocoo.platform.common.utils.upload;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Zip文件工具类
 *
 * @author L
 * @version 1.0
 * @since 2018-8-17, 下午05:04:47
 */
public class ZipFileUtil {


    /**
     * 把文件压缩成zip格式 {method description}
     *
     * @param files       需要压缩的文件
     * @param zipFilePath 压缩后的zip文件路径 ,如"D:/test/aa.zip";
     * @author zhmi
     */
    public static void compressFilesZip(File[] files, String zipFilePath) {
        if (files != null && files.length > 0) {
            if (isEndsWithZip(zipFilePath)) {
                ZipArchiveOutputStream zaos = null;
                try {
                    File zipFile = new File(zipFilePath);
                    zaos = new ZipArchiveOutputStream(zipFile);
                    // Use Zip64 extensions for all entries where they are
                    // required
                    zaos.setUseZip64(Zip64Mode.AsNeeded);
                    // 将每个文件用ZipArchiveEntry封装
                    // 再用ZipArchiveOutputStream写到压缩文件中
                    for (File file : files) {
                        if (file != null) {
                            if (file.exists()) {
                                ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(file, file.getName());
                                zaos.putArchiveEntry(zipArchiveEntry);
                                InputStream is = null;
                                try {
                                    is = new BufferedInputStream(new FileInputStream(file));
                                    byte[] buffer = new byte[1024 * 5];
                                    int len = -1;
                                    while ((len = is.read(buffer)) != -1) {
                                        // 把缓冲区的字节写入到ZipArchiveEntry
                                        zaos.write(buffer, 0, len);
                                    }
                                    // Writes all necessary data for this entry.
                                    zaos.closeArchiveEntry();
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                } finally {
                                    if (is != null)
                                        is.close();
                                }

                            }else {
                                System.out.println(file+"==============>待压缩文件不存在");
                            }
                        }else {
                            System.out.println(file+"==============>待压缩文件不存在");
                        }
                    }
                    zaos.finish();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    try {
                        if (zaos != null) {
                            zaos.close();
                        }
                    } catch (IOException e) {

                        throw new RuntimeException(e);
                    }
                }

            }

        }
    }

    /**
     * 把zip文件解压到指定的文件夹
     *
     * @param zipFilePath zip文件路径, 如 "D:/test/aa.zip"
     * @param saveFileDir 解压后的文件存放路径, 如"D:/test/"
     * @author zhmi
     */
    public static void decompressZip(String zipFilePath, String saveFileDir) {
        if (isEndsWithZip(zipFilePath)) {
            File file = new File(zipFilePath);
            if (file.exists()) {
                InputStream is = null;
                // can read Zip archives
                ZipArchiveInputStream zais = null;
                try {
                    is = new FileInputStream(file);
                    zais = new ZipArchiveInputStream(is);
                    ArchiveEntry archiveEntry = null;
                    // 把zip包中的每个文件读取出来
                    // 然后把文件写到指定的文件夹
                    while ((archiveEntry = zais.getNextEntry()) != null) {
                        // 获取文件名
                        String entryFileName = archiveEntry.getName();
                        // 构造解压出来的文件存放路径
                        String entryFilePath = saveFileDir + entryFileName;
                        byte[] content = new byte[(int) archiveEntry.getSize()];
                        zais.read(content);
                        OutputStream os = null;
                        try {
                            // 把解压出来的文件写到指定路径
                            File entryFile = new File(entryFilePath);
                            os = new BufferedOutputStream(new FileOutputStream(entryFile));
                            os.write(content);
                        } catch (IOException e) {
                            throw new IOException(e);
                        } finally {
                            if (os != null) {
                                os.flush();
                                os.close();
                            }
                        }

                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    try {
                        if (zais != null) {
                            zais.close();
                        }
                        if (is != null) {
                            is.close();
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

    /**
     * 判断文件名是否以.zip为后缀
     *
     * @param fileName 需要判断的文件名
     * @return 是zip文件返回true, 否则返回false
     * @author zhmi
     */
    public static boolean isEndsWithZip(String fileName) {
        boolean flag = false;
        if (fileName != null && !"".equals(fileName.trim())) {
            if (fileName.endsWith(".ZIP") || fileName.endsWith(".zip")) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 将存放在sourceFilePath目录下的源文件，打包成fileName名称的zip文件，并存放到zipFilePath路径下
     *
     * @param sourceFilePath :待压缩的文件路径
     * @param zipFilePath    :压缩后存放路径
     * @param fileName       :压缩后文件的名称
     * @return:压缩后的文件路径+名称+后缀
     */
    public static String fileToZip(String sourceFilePath, String zipFilePath, String fileName) {
        boolean flag = false;
        File sourceFile = new File(sourceFilePath);
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        ZipOutputStream zos = null;

        if (sourceFile.exists() == false) {
            System.out.println("待压缩的文件目录：" + sourceFilePath + "不存在.");
        } else {
            try {
                File zipFile = new File(zipFilePath + "/" + fileName + ".zip");
                if (zipFile.exists()) {
                    zipFile.delete();
                    System.out.println("删除" + zipFilePath + "目录下存在名字为:" + fileName + ".zip" + "打包文件.");
                }
                File[] sourceFiles = sourceFile.listFiles();
                if (null == sourceFiles || sourceFiles.length < 1) {
                    System.out.println("待压缩的文件目录：" + sourceFilePath + "里面不存在文件，无需压缩.");
                } else {
                    fos = new FileOutputStream(zipFile);
                    zos = new ZipOutputStream(new BufferedOutputStream(fos));
//                    zos.setEncoding("gbk");
                    zos.setComment(fileName);
                    byte[] bufs = new byte[1024 * 10];
                    for (int i = 0; i < sourceFiles.length; i++) {
                        // 创建ZIP实体，并添加进压缩包
                        ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());
                        zos.putNextEntry(zipEntry);
                        // 读取待压缩的文件并写进压缩包里
                        fis = new FileInputStream(sourceFiles[i]);
                        bis = new BufferedInputStream(fis, 1024 * 10);
                        int read = 0;
                        while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {
                            zos.write(bufs, 0, read);
                        }
                    }
                    flag = true;
                    System.out.println("打包成功，文件路径：" + zipFilePath);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } finally {
                // 关闭流
                try {
                    if (null != bis)
                        bis.close();
                    if (null != zos) {
                        zos.flush();
                        zos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
        }
        if (flag)
            return zipFilePath + "/" + fileName + ".zip";
        return null;
    }


}
